﻿using System.Collections.Generic;
using System.Threading;
using System;

namespace xshare
{


    /// <summary>
    /// 用于异步线程和主线程交互(通信)
    /// </summary>
    public static class MainThreadSync
    {

        public class SyncMsgData
        {
            public object obj;
            public int i;
            public string s;

            internal void Reset()
            {
                obj = null;
                i = 0;
                s = "";
            }
        }

        /// <summary>
        /// 交互消息
        /// </summary>
        public class SyncMsg
        {
            internal Action<SyncMsgData> _func;

            internal SyncMsgData _userData = new SyncMsgData();

            internal bool _invalid = false;

            public void SetInvalid()
            {
                _invalid = true;
            }
 
            internal void Reset()
            {
                _func = null;
                _userData.Reset();
                _invalid = false;
            }

        } //end of class



        static Pool<SyncMsg> s_criticalMsgPool; //主线程和异步线程都会从这个pool获取消息

        static List<SyncMsg> s_criticalMsgList; //异步线程在这边添加消息, 主线程在这边获取消息
        static List<SyncMsg> s_mainThreadMsgList;

        static int s_mainThreadId;

        internal static void Initialize()
        {
            s_criticalMsgPool = new Pool<SyncMsg>((sender) => new SyncMsg(), (sender, msg) => { msg.Reset(); });

            s_criticalMsgList = new List<SyncMsg>();
            s_mainThreadMsgList = new List<SyncMsg>();

            s_mainThreadId = Thread.CurrentThread.ManagedThreadId;
        }

        internal static void OnUpdate()
        {
            if (s_criticalMsgList.Count > 0)
            {
                if (Monitor.TryEnter(s_criticalMsgList))
                {
                    try
                    {
                        if (s_criticalMsgList.Count > 0)
                        {
                            s_mainThreadMsgList.AddRange(s_criticalMsgList);
                            s_criticalMsgList.Clear();
                        }
                    }
                    finally
                    {
                        Monitor.Exit(s_criticalMsgList);
                    }
                }
            }

            var ct = s_mainThreadMsgList.Count;
            if (ct > 0)
            {
                int removeCount = 0;
                for (var i = 0; i < ct; ++i)
                {
                    var msg = s_mainThreadMsgList[i];
                    if (null == msg)
                        continue;

                    if (false == msg._invalid)
                        DelegateUtils.SafeInvoke(msg._func, msg._userData);

                    RecycleMsg(msg);
                    s_mainThreadMsgList[i] = null;
                    removeCount++;
                }

                //清理List
                if (removeCount > 0)
                {
                    for (var i = ct - 1; i >= 0; --i)
                    {
                        var msg = s_mainThreadMsgList[i];
                        if (null == msg)
                            s_mainThreadMsgList.RemoveAt(i);
                    }
                }
            }
        }

        static void RecycleMsg(SyncMsg msg)
        {
            if (Monitor.TryEnter(s_criticalMsgPool)) //失败就不回收
            {
                try
                {
                    s_criticalMsgPool.Recycle(msg);
                }
                finally
                {
                    Monitor.Exit(s_criticalMsgPool);
                }
            }
        }

        public static SyncMsgData QueueOnMainThread(Action<SyncMsgData> func)
        {
            SyncMsg msg;
            lock (s_criticalMsgPool)
                msg = s_criticalMsgPool.Obtain();
            msg._func = func;

            lock (s_criticalMsgList)
                s_criticalMsgList.Add(msg);

            return msg._userData;
        }


    } //end of class

}
